﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Word.Editor.Doc
{
    /// <summary>
    /// The ChpxFkp structure maps text to its character properties. 
    /// A ChpxFkp structure is 512 bytes in size, with crun in the last byte. 
    /// The elements of rgb point to Chpxs that start at offsets between crun and the end of rgb.
    /// pag. 237
    /// </summary>
    public class ChpxFkp:PLC
    {
        public ChpxFkp():base()
        { }

        public Byte crun = 0;
        /// <summary>
        /// An array of 4-byte unsigned integers. 
        /// Each element of this array specifies an offset in the WordDocument Stream where a run of text begins. 
        /// This array MUST be sorted in ascending order and MUST NOT contain duplicates. Each run ends at the beginning of the next run. 
        /// This array contains crun+1 elements, where the last element specifies the end of the last run.
        /// </summary>
        public UInt32[] rgfc = null;

        /// <summary>
        /// An array of 1-byte unsigned integers, followed by an array of Chpx structures. The elements of this array, which has crun elements and parallels rgfc, each specify the
        /// offset of one of the Chpxs within this ChpxFkp. The offset is computed by multiplying the value of the byte by 2.
        /// </summary>
        public Byte[] rgb = null;

        public Chpx[] _chpx = null; 

        public override void ParseBuffer(byte[] buffer)
        {
            if (buffer.Length <= 0 || buffer.Length >512 )
                throw new ArgumentOutOfRangeException(Strings.Buffer_LenghtOutOfRange);

            crun = buffer[511];
            rgfc = new UInt32[crun + 1];
            if (crun == 0)
                throw new IndexOutOfRangeException(Strings.DataArraySize_InvalidValue);
            rgb = new Byte[crun];

            for (int i = 0; i < crun + 1; i++)
            {
                rgfc[i] = GetUint32(buffer, i * 4);
            }
            for (int i = 0; i < crun; i++)
            {
                rgb[i] = GetByte(buffer, (crun + 1) * 4 + i);
            }
            ReadAllChpxStructure(buffer);
            
        }

        private void ReadAllChpxStructure(byte[] buffer)
        {
            _chpx = new Chpx[crun];
            for (int i = 0; i < crun; i++)
            {
                _chpx[i] = new Chpx();
                _chpx[i].cb = (byte)GetByte(buffer, rgb[i]*2);
                List<Prl> tmpList = new List<Prl>();
                int prlByteRead = 0;
                while (prlByteRead < _chpx[i].cb)
                {
                    Prl tmp = new Prl(PLC.GetUint16(buffer, rgb[i] * 2+1));
                    prlByteRead += 2;
                    prlByteRead += tmp.sprm.lgOperand;
                    tmp.operand = GetBytes(buffer, rgb[i] * 2 + 3, tmp.sprm.lgOperand);
                    tmpList.Add(tmp);
                    if (tmp.sprm.lgOperand == 100)
                        break;
                }
                _chpx[i].grpprl = tmpList.ToArray();
            }
        }

        internal void AddToTree(System.Windows.Forms.TreeNode root)
        {
            TreeNode aCPTN = root.Nodes.Add("rgfc");
            for (int i = 0; i < crun + 1; i++)
            {
                aCPTN.Nodes.Add("rgfc" + i.ToString(), string.Format("{0}={1:X}", i, rgfc[i]));
            }
            TreeNode aPcdTN = root.Nodes.Add("rgb");
            for (uint i = 0; i < crun; i++)
            {
                aPcdTN.Nodes.Add("rgb" + i.ToString(), string.Format("{0}={1:X}", i, rgb[i]));
            }
            root.Nodes.Add("ChpxFkp.crun", string.Format("crun={0:X}", crun));
            TreeNode chpxTN = root.Nodes.Add("chpx");
            for (uint i = 0; i < crun; i++)
            {
                TreeNode tntmp = chpxTN.Nodes.Add("chpx" + i.ToString(), string.Format("Chpx[{0}]", i));
                tntmp.Nodes.Add("chpx" + i.ToString() + ".cb", string.Format("cb = {0:X}", _chpx[i].cb));
                TreeNode grpprltn = tntmp.Nodes.Add("chpx" + i.ToString() + ".grpprl", string.Format("grpprl"));
                for (int j = 0; j < _chpx[i].grpprl.Length; j++)
                {
                    grpprltn.Nodes.Add("rgb" + i.ToString() + ".grpprl" + j.ToString(), string.Format("{0}={1:X},lg={2},sgc={3},ispmd={4:X},spra={5}", j, _chpx[i].grpprl[j].sprm.valueRead, _chpx[i].grpprl[j].sprm.lgOperand, _chpx[i].grpprl[j].sprm.sgc, _chpx[i].grpprl[j].sprm.ispmd, _chpx[i].grpprl[j].sprm.spra));
                }
            }
        }
    }

    /// <summary>
    /// The Chpx structure specifies a set of properties for text.
    /// </summary>
    public class Chpx
    {
        /// <summary>
        /// An unsigned integer that specifies the size of grpprl, in bytes.
        /// </summary>
        public Byte cb=0;
        /// <summary>
        /// An array of Prl. Specifies the properties. This array MUST contain a whole number of Prls.
        /// </summary>
        public Prl[] grpprl=null;
    }
}
